home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ov143b.zip / OVDIR.C < prev    next >
C/C++ Source or Header  |  1993-01-04  |  26KB  |  751 lines

  1. /*  036  8-Jun-87  ovdir.c
  2.  
  3.         Copyright (c) 1987 by Blue Sky Software.  All rights reserved.
  4. */
  5.  
  6. #include <stdio.h>
  7. #include "ov.h"
  8. #include "overr.h"
  9. #include "menu.h"
  10. #include "direct.h"
  11. #include "strmem.h"
  12. #include "dosfile.h"
  13.  
  14. #define DCOLSIZ 15
  15. #define DCOLS (SCREEN_COLS / DCOLSIZ)
  16.  
  17. #define dr2sr(r) (FIRST_NROW + (r - drbase))
  18. #define dc2sc(c) ((c - dcbase) * DCOLSIZ)
  19.  
  20. #define TO_NONE 0
  21. #define TO_SUBDIR 1
  22. #define TO_SIBLING 2
  23. #define TO_PARENT 3
  24. #define TO_ROOT 4
  25.  
  26. char *strrchr(), *strupr();
  27. struct search_block *nxtfile();
  28.  
  29. struct dir_ent {
  30.    struct dir_ent *subdir;
  31.    struct dir_ent *sibling;
  32.    struct dir_ent *parent;
  33.    struct dir_ent *prev_sib;
  34.    char name[13];
  35.    unsigned char row;
  36.    unsigned char col;
  37. };
  38.  
  39. static last_drive = ' ';
  40. static char dirpath[MAX_PATHLEN+6];
  41. static int drbase, drend, dcbase, dcend;
  42. static struct dir_ent *curdir, *logdir, *findir(), *dir_next();
  43. static struct dir_ent root = { NULL, NULL, NULL, NULL, "", 0, 0 };
  44.  
  45. int dir_exit(), dir_login(), dir_mkdir(), dir_rmdir(), dir_new();
  46. extern MENU top_file_menu[], *top_menu;
  47.  
  48. MENU top_dir_menu[] = {
  49.    { "Login", "Login (switch) to the highlighted directory", dir_login, NULL },
  50.    { "Mkdir", "Make a subdirectory of the highlighted directory", dir_mkdir, NULL },
  51.    { "New", "Reread and redisplay directory tree", dir_new, NULL },
  52.    { "Rmdir", "Remove (delete) the highlighted directory", dir_rmdir, NULL },
  53.    { "Quit", "Return to file display", dir_exit, top_file_menu },
  54.    { NULL, NULL, NULL, NULL }
  55. };
  56.  
  57. extern WINDOW cw;
  58. extern unsigned char dir_display, restricted;
  59. char *strchr();
  60.  
  61.  
  62. /******************************************************************************
  63.  **                            D T R E E                                     **
  64.  *****************************************************************************/
  65.  
  66. dtree() {              /* display / work with directory tree */
  67.  
  68.    int drive;
  69.  
  70.    dir_display = TRUE;                 /* dir tree is (will be) displayed */
  71.    restricted = TRUE;                  /* disable some file commands */
  72.  
  73.    /* scan the current disk and create the internal directory tree if it
  74.       hasn't already been built or the user has changed disks */
  75.  
  76.    if ((drive = current_drive()) != last_drive) {  /* has the drive switched? */
  77.  
  78.       if (root.subdir) {                       /* delete current tree */
  79.          del_dtree(root.subdir);               /* if drive switch */
  80.          root.subdir = NULL;
  81.       }
  82.  
  83.       last_drive = drive;
  84.  
  85.       *dirpath = '\0';                         /* scan_dir() starts at */
  86.       strncat(dirpath,cw.dirbuf,3);            /*   drives root dir */
  87.       strcpy(root.name,dirpath);
  88.  
  89.       disp_msg(1,"Scanning disk");             /* takes awhile, tell user */
  90.  
  91.       scan_dir(&root);                         /* build new dir tree */
  92.       dir_mark();                              /* assign row/col's to ent's */
  93.  
  94.       clr_msg();                               /* done scanning */
  95.  
  96.       drbase = dcbase = 0;                     /* assume dir */
  97.       drend = NAME_ROWS;                         /* will start */
  98.       dcend = DCOLS;                               /* at the root */
  99.    }
  100.  
  101.    curdir = findir();                  /* locate current dir in tree */
  102.  
  103.    logdir = curdir;                    /* remember the logged dir */
  104.  
  105.    /* now display the current portion of the dir tree */
  106.  
  107.    adj_dir_dis();                      /* make sure logged dir will show */
  108.    dir_distree();                      /* let user see it */
  109.  
  110.    top_menu = top_dir_menu;    /* setup the dir menu as the main menu */
  111. }
  112.  
  113.  
  114. /******************************************************************************
  115.                               D I R _ N E W
  116.  *****************************************************************************/
  117.  
  118. dir_new() {            /* rescan the disk and redisplay the dir tree */
  119.  
  120.    last_drive = ' ';   /* simply force a rescan */
  121.    dtree();            /*   and let dtree() do the work */
  122.    update_vol_stats(); /* in case its a new volume */
  123. }
  124.  
  125.  
  126. /******************************************************************************
  127.  **                       D I R _ E X I T                                    **
  128.  *****************************************************************************/
  129.  
  130. dir_exit() {           /* exit the dir display, return to file display */
  131.  
  132.    dir_display = FALSE;                /* dir tree will not be displayed */
  133.    restricted = FALSE;                 /* allow all file commands */
  134.  
  135.    top_menu = top_file_menu;           /* file menu is main again */
  136.  
  137.    update_header();                    /* always rewrite the entire screen */
  138.    refresh_screen(0);                  /* 'cause there may be > windows */
  139. }
  140.  
  141.  
  142. /******************************************************************************
  143.  **                         S C A N _ D I R                                  **
  144.  *****************************************************************************/
  145.  
  146. scan_dir(dp)           /* scan the specified dir tree for other directories */
  147. struct dir_ent *dp;
  148. {
  149.    int dplen;
  150.    int firsttime = TRUE;
  151.    struct search_block *sbp;
  152.    register struct dir_ent *ndp, *ldp = NULL;
  153.  
  154.    /* build the pathname of the dir to scan */
  155.  
  156.    dplen = strlen(dirpath);                    /* remember callers length */
  157.    if (strcmp(dp->name+2,"\\") != 0) {         /* special case if root dir */
  158.       strcat(dirpath,dp->name);                /* add name of dir to scan */
  159.       strcat(dirpath,"\\");
  160.    }
  161.    strcat(dirpath,"*.*");                      /* add wildcard string */
  162.  
  163.    /* scan all files in directory looking for subdirectories.  When a
  164.       subdirectory is found, add it to the dir_ent tree.  Note, the . and
  165.       .. directory entries are ignored. */
  166.  
  167.    while (sbp = nxtfile(dirpath,0x16,&firsttime))
  168.       if (sbp->attrib & DIR && *sbp->fn != '.') {
  169.  
  170.          /* found a subdir we want, build a struct dir_ent for it */
  171.          ndp = (struct dir_ent *) Malloc(sizeof(struct dir_ent));
  172.          strcpy(ndp->name,sbp->fn);
  173.          ndp->subdir = NULL;
  174.          ndp->sibling = NULL;
  175.          ndp->parent = dp;
  176.          ndp->prev_sib = ldp;
  177.  
  178.          /* now link it to the dir_ent tree either as a subdir of the
  179.             parent (1st one only) or a sibling of the last one */
  180.  
  181.          if (ldp)
  182.             ldp->sibling = ndp;        /* not 1st, is a sibling */
  183.          else
  184.             dp->subdir = ndp;          /* 1st one, subdir of parent */
  185.  
  186.          ldp = ndp;                    /* new one is now the last one */
  187.       }
  188.  
  189.    /* if any subdirectories were found, scan 'em.  This isn't done
  190.       earlier so the file search isn't complicated by the directory
  191.       switches. */
  192.  
  193.    if (ldp) {                            /* NULL if no sub's found */
  194.       dirpath[strlen(dirpath)-3] = '\0'; /* remove *.* for next level */
  195.       ldp = dp->subdir;                  /* start with the first one */
  196.       do {
  197.          scan_dir(ldp);                /* call ourselves to scan this subtree */
  198.       } while (ldp = ldp->sibling);    /* do all the subs found */
  199.    }
  200.  
  201.    dirpath[dplen] = '\0';              /* restore dir pathname for caller */
  202. }
  203.  
  204.  
  205. /******************************************************************************
  206.  **                           D E L _ D T R E E                              **
  207.  *****************************************************************************/
  208.  
  209. del_dtree(dp)          /* purge the current in memory dir tree structure */
  210. register struct dir_ent *dp;
  211. {
  212.  
  213.    register struct dir_ent *ndp;
  214.  
  215.    /* delete this subdirectory ENTRY and all sibling ENTRIES (not the
  216.       actual directories) */
  217.  
  218.    do {
  219.  
  220.       if (dp->subdir)            /* if it has a subdir, make a recursive call */
  221.          del_dtree(dp->subdir);  /* to delete the substructure */
  222.  
  223.       ndp = dp->sibling;         /* get address of any sibling */
  224.  
  225.       free((char *)dp);          /* free the dir_ent space itself */
  226.  
  227.    } while (dp = ndp);           /* do until no more siblings */
  228.  
  229. }
  230.  
  231.  
  232. /******************************************************************************
  233.                            D I R _ D I S T R E E
  234.  *****************************************************************************/
  235.  
  236. static int
  237. dir_distree() {        /* display the dir tree */
  238.  
  239.    register int drow;
  240.    int i, ldrow = -1;
  241.    register struct dir_ent *dp = &root;
  242.  
  243.    do {
  244.  
  245.       drow = dp->row;          /* speed things up a little */
  246.  
  247.       /* if drow != ldrow, then this is the first entry on this display
  248.          row, clear the line to remove any old junk that might be there */
  249.  
  250.       if (drow != ldrow && drow >= drbase && drow < drend) {
  251.          gotorc(dr2sr(drow),dc2sc(dcbase));
  252.          clr_eol();
  253.          ldrow = drow;
  254.       }
  255.  
  256.       /* see if its necessary to put some spacer bars in from the previous
  257.          sibling.  This will be necessary if the prev_sib had a desendent
  258.          with siblings because the siblings will occupy display lines
  259.          between this ent's prev_sib and where this ent goes. */
  260.  
  261.       if (dp->prev_sib && (i = drow - dp->prev_sib->row - 1) > 0)
  262.          for (; i; i--)
  263.             if (dir_on_screen(drow-i,dp->col))
  264.                disp_char_at(0xb3,dr2sr(drow-i),dc2sc(dp->col));
  265.  
  266.       /* only display a dir entry if it falls within the boundries, figure
  267.          out if this one does and display the name if so - the dir under
  268.          the pointer is highlighted, the logged dir is 'tagged' all others
  269.          are displayed 'normal' */
  270.  
  271.       if (dir_on_screen(drow,dp->col))
  272.          disp_dir_name(dp,dp == curdir ? DIS_HIGH :
  273.                        (dp == logdir ? DIS_TAGD : DIS_NORM));
  274.  
  275.    } while (dp = dir_next(dp,&i,&i));
  276.  
  277.    /* if we didn't reach the bottom of the display area, clear out the rest
  278.       of the lines to remove any garbage that might be there */
  279.  
  280.    drow++;                             /* next would be display row */
  281.    if (drow - drbase < NAME_ROWS)
  282.       for (; drow - drbase < NAME_ROWS; drow++) {
  283.          gotorc(dr2sr(drow),dc2sc(dcbase));
  284.          clr_eol();
  285.       }
  286. }
  287.  
  288.  
  289. /******************************************************************************
  290.  **                    D I S P _ D I R _ N A M E                             **
  291.  *****************************************************************************/
  292.  
  293. disp_dir_name(dp,va)   /* display a single dir name */
  294. register struct dir_ent *dp;
  295. int va;
  296. {
  297.    gotorc(dr2sr(dp->row),dc2sc(dp->col));      /* move to display location */
  298.  
  299.    /* display the leadin bar to the dir name, it depends on whether
  300.       this is the root, the 1st subdir, the last sibling, and if any
  301.       siblings follow */
  302.  
  303.    if (dp->col) {                                 /* root dir? */
  304.       if (dp->prev_sib == NULL)                   /* 1st subdir? */
  305.          disp_char((dp->sibling) ? 0xc2 : 0xc4);  /* siblings follow? */
  306.       else
  307.          disp_char((dp->sibling) ? 0xc3 : 0xc0);
  308.    } else
  309.       disp_char(' ');                          /* root - no leadin */
  310.  
  311.    if (va != DIS_NORM)                         /* setup highlight if needed */
  312.       setvattrib(va);
  313.  
  314.    disp_char(' ');
  315.    disp_str(dp->name);                         /* display the name */
  316.    disp_char(' ');
  317.  
  318.    /* draw bar to subdir or blank fill name */
  319.  
  320.    disp_rep(dp->subdir ? 0xc4 : ' ',DCOLSIZ - strlen(dp->name) - 3);
  321.  
  322.    if (va != DIS_NORM)         /* restore normal attribute if changed */
  323.       setvattrib(DIS_NORM);
  324. }
  325.  
  326.  
  327. /*****************************************************************************
  328.                              D I R _ M A R K
  329.  *****************************************************************************/
  330.  
  331. static int
  332. dir_mark() {   /* mark dir_ent's with logical row/column where they display */
  333.  
  334.    register struct dir_ent *dp;
  335.    int nxtype, backup, drow, dcol;
  336.  
  337.    dp = &root;
  338.    drow = dcol = 0;
  339.  
  340.    /* scan the dir_ent tree in order */
  341.  
  342.    while (dp = dir_next(dp,&nxtype,&backup)) {
  343.       if (nxtype) {                            /* NZ if dp is a sibling */
  344.          drow++;                               /* siblings go down a row */
  345.          dcol -= backup;                       /* and maybe back some */
  346.       } else
  347.          dcol++;                               /* sub dir's go over a column */
  348.       dp->row = drow;                          /* assign row/col to entry */
  349.       dp->col = dcol;
  350.    }
  351. }
  352.  
  353.  
  354. /******************************************************************************
  355.                                D I R _ N E X T
  356.  ******************************************************************************/
  357.  
  358. static struct dir_ent *
  359. dir_next(dp,tp,bp)     /* return address of next dir_ent */
  360. register struct dir_ent *dp;
  361. int *tp, *bp;
  362. {
  363.    *bp = 0;                    /* assume we will not backup to parent */
  364.  
  365.    if (dp->subdir) {           /* subdir is next if there is one */
  366.       *tp = 0;                 /* tell caller its a sub dir */
  367.       return(dp->subdir);
  368.    }
  369.  
  370.    *tp = 1;                    /* assume a sibling will be found */
  371.  
  372.    if (dp->sibling)            /* a sibling is next if there is one */
  373.       return(dp->sibling);
  374.  
  375.    /* keep backing up until a parent is found with a sibling or root */
  376.  
  377.    while ((dp = dp->parent) && dp != &root) {
  378.       (*bp)++;                         /* tell caller # levels backed up */
  379.       if (dp->sibling)
  380.          return(dp->sibling);
  381.    }
  382.  
  383.    return(NULL);               /* no more dir ents to be found */
  384. }
  385.  
  386.  
  387. /******************************************************************************
  388.                                D I R _ M O V E
  389.  *****************************************************************************/
  390.  
  391. dir_move(move_cmd)     /* move the directory pointer around */
  392. int move_cmd;
  393. {
  394.    int moved = TO_NONE;
  395.    int redisplayed = FALSE;
  396.    register struct dir_ent *last_dir, *cdp;
  397.  
  398.    last_dir = cdp = curdir;    /* remember where we are/were and fast ptr */
  399.  
  400.    switch (move_cmd) {
  401.  
  402.       case RIGHT:
  403.          if (cdp->subdir) {
  404.             cdp = cdp->subdir;
  405.             moved = TO_SUBDIR;
  406.          } else
  407.             if (cdp->sibling) {
  408.                cdp = cdp->sibling;
  409.                moved = TO_SIBLING;
  410.             }
  411.             /* stuff about parents goes here */
  412.          break;
  413.  
  414.       case LEFT:
  415.          if (cdp->prev_sib) {
  416.             cdp = cdp->prev_sib;
  417.             moved = TO_SIBLING;
  418.          } else
  419.             if (cdp->parent) {
  420.                cdp = cdp->parent;
  421.                moved = TO_PARENT;
  422.             }
  423.          break;
  424.  
  425.       case UP:
  426.          if (cdp->prev_sib) {
  427.             cdp = cdp->prev_sib;
  428.             moved = TO_SIBLING;
  429.          }
  430.          break;
  431.  
  432.       case DOWN:
  433.          if (cdp->sibling) {
  434.             cdp = cdp->sibling;
  435.             moved = TO_SIBLING;
  436.          }
  437.          break;
  438.  
  439.       case HOME:
  440.          cdp = &root;
  441.          moved = TO_ROOT;
  442.          break;
  443.  
  444.       case GOPAR:
  445.          if (cdp->parent) {
  446.             cdp = cdp->parent;
  447.             moved = TO_PARENT;
  448.          }
  449.       break;
  450.  
  451.    }
  452.  
  453.    curdir = cdp;           /* assign it */
  454.  
  455.    /* adjust and redisplay the pathname as the user moves the dir pointer */
  456.  
  457.    if (moved != TO_NONE)
  458.       update_dirpath(moved);
  459.  
  460.    /* display a different section of dir tree if current isn't displayed */
  461.  
  462.    if (adj_dir_dis()) {                /* is adjustment needed? */
  463.       dir_distree();                   /* display the tree */
  464.       redisplayed = TRUE;              /* save a disp_dir_name() call */
  465.    }
  466.  
  467.    /* deselect the last dir if the dir pointer moved and the last one
  468.       is still on the screen and the entire tree wasn't redisplayed */
  469.  
  470.    if (!redisplayed && last_dir != curdir &&
  471.        dir_on_screen(last_dir->row,last_dir->col))
  472.       disp_dir_name(last_dir,last_dir == logdir ? DIS_TAGD : DIS_NORM);
  473.  
  474.    /* select (highlight) a new dir entry if pointer moved and the tree
  475.       wasn't redisplayed */
  476.  
  477.    if (last_dir != curdir && !redisplayed) {
  478.       disp_dir_name(curdir,DIS_HIGH);
  479.    }
  480. }
  481.  
  482.  
  483. /******************************************************************************
  484.  **                       D I R _ L O G I N                                  **
  485.  *****************************************************************************/
  486.  
  487. dir_login() {          /* login the dir selected by the dir pointer */
  488.  
  489.    /* switch to selected dir, if can't switch, user may have changed
  490.       disks, force a scan of the disk for dirs */
  491.  
  492.    if (switch_dir(dirpath) != 0)       /* switch to the selected dir */
  493.       last_drive = ' ';
  494.  
  495.    dir_exit();                         /* exit the dir display mode */
  496.  
  497. }
  498.  
  499.  
  500. /******************************************************************************
  501.  **                       D I R _ R M D I R                                  **
  502.  *****************************************************************************/
  503.  
  504. dir_rmdir() {          /* remove the dir selected by the dir pointer */
  505.  
  506.    int moveto;
  507.    register struct dir_ent *cdp;
  508.  
  509.    cdp = curdir;               /* try to reduce code size */
  510.  
  511.    /* don't even let user try to delete the root or current directories */
  512.  
  513.    if (cdp->col == 0 || strcmp(dirpath,cw.dirbuf) == 0)
  514.       show_error(0,CANT_RMDIR,3,"You can't delete the ",(cdp->col == 0) ? "root" :
  515.                 "current"," directory!");
  516.  
  517.    /* use DOS to acutally remove the directory */
  518.  
  519.    if (rmdir(dirpath) != 0)
  520.       show_error(SHOW_DOS,CANT_RMDIR,1,"Unable to remove dir: ");
  521.  
  522.    /* Okay, the dir is gone, now remove it from the dir tree */
  523.  
  524.    if (cdp->prev_sib)                                  /* make prev sib -> */
  525.       cdp->prev_sib->sibling = cdp->sibling;           /* next sib */
  526.  
  527.    if (cdp->sibling) {                                 /* next sib -> */
  528.       cdp->sibling->prev_sib = cdp->prev_sib;          /* prev sib && */
  529.       if (cdp->parent->subdir == cdp)                  /* parent ->   */
  530.          cdp->parent->subdir = cdp->sibling;           /* next sib    */
  531.    }
  532.  
  533.    if (cdp->prev_sib == NULL && cdp->sibling == NULL)  /* parent has no */
  534.       cdp->parent->subdir = NULL;                      /* more sub's */
  535.  
  536.    /* when deleting a subdirectory, try to make a sibling the current dir,
  537.       if none, go back to parent */
  538.  
  539.    if (cdp->sibling) {
  540.       curdir = cdp->sibling;
  541.       moveto = TO_SIBLING;
  542.    } else
  543.       if (cdp->prev_sib) {
  544.          curdir = cdp->prev_sib;
  545.          moveto = TO_SIBLING;
  546.       } else {
  547.          curdir = cdp->parent;
  548.          moveto = TO_PARENT;
  549.       }
  550.  
  551.    update_vol_stats();         /* should be more free space now */
  552.  
  553.    update_dirpath(moveto);     /* show user what the dir pathname is */
  554.  
  555.    free((char *)cdp);          /* release mem used by the dir entry */
  556.  
  557.    dir_mark();         /* reassign row/column values for remaining dir's */
  558.    adj_dir_dis();      /* make sure the current dir will display */
  559.    dir_distree();      /* redisplay updated dir tree */
  560. }
  561.  
  562.  
  563. /******************************************************************************
  564.  **                       D I R _ M K D I R                                  **
  565.  *****************************************************************************/
  566.  
  567. dir_mkdir() {          /* make a subdirectory in the selected dir */
  568.  
  569.    int rc;
  570.    char *name, *dirend;
  571.    register struct dir_ent *ndp, *ldp;
  572.  
  573.    /* ask user what to call the new directory */
  574.  
  575.    name = strupr(prompt(NULL,"Enter the new subdirectory name: ",NULL,0,12));
  576.    if (strlen(name) == 0)
  577.       return;
  578.  
  579.    /* update dirpath to include the users new name */
  580.  
  581.    dirend = dirpath + strlen(dirpath); /* remember current dirpath end */
  582.    if (*(dirend-1) != '\\')
  583.       strcat(dirend,"\\");
  584.    strcat(dirend,name);                /* add users dir name */
  585.  
  586.    /* use DOS to acutally make the directory */
  587.  
  588.    rc = mkdir(dirpath);                /* create it */
  589.  
  590.    *dirend = '\0';                     /* fixup dirpath */
  591.  
  592.    if (rc != 0)
  593.       show_error(SHOW_DOS,CANT_MKDIR,1,"Unable to make dir: ");
  594.  
  595.    /* Okay, the dir is created, now make a dir_ent and add it to the dir tree */
  596.  
  597.    ndp = (struct dir_ent *) Malloc(sizeof(struct dir_ent));
  598.    strcpy(ndp->name,name);
  599.    ndp->subdir = NULL;
  600.    ndp->sibling = NULL;
  601.    ndp->parent = curdir;
  602.  
  603.    if (ldp = curdir->subdir) {                 /* any sibs to new dir? */
  604.       while (ldp->sibling)                     /* find end of sib list */
  605.          ldp = ldp->sibling;
  606.       ndp->prev_sib = ldp;                     /* new one is last */
  607.       ldp->sibling = ndp;
  608.    } else {
  609.       ndp->prev_sib = NULL;                    /* no sibs */
  610.       curdir->subdir = ndp;                    /* parent now has subdir */
  611.    }
  612.  
  613.    update_vol_stats();                 /* less free space now */
  614.  
  615.    dir_mark();         /* assign new row/col values */
  616.    dir_distree();      /* redisplay dir tree */
  617. }
  618.  
  619.  
  620. /******************************************************************************
  621.  **                    U P D A T E _ D I R P A T H                           **
  622.  *****************************************************************************/
  623.  
  624. static int
  625. update_dirpath(moved)          /* update & redisplay dir path */
  626. int moved;
  627. {
  628.    char *cp;
  629.  
  630.    switch (moved) {
  631.  
  632.       case TO_SUBDIR:                  /* moved to a subdir */
  633.          if (curdir->col != 1)         /* append a \ if parent wasn't root */
  634.             strcat(dirpath,"\\");
  635.          strcat(dirpath,curdir->name); /* append the subdirectory name */
  636.          break;
  637.  
  638.       case TO_SIBLING:                 /* moved to a sibling */
  639.          *(strrchr(dirpath,'\\')+1) = '\0';
  640.          strcat(dirpath,curdir->name);
  641.          break;
  642.  
  643.       case TO_PARENT:                  /* moved to parent */
  644.          cp = strrchr(dirpath,'\\');
  645.          if (curdir->col == 0)
  646.             ++cp;
  647.          *cp = '\0';
  648.          break;
  649.  
  650.       case TO_ROOT:                    /* moved to the root */
  651.         dirpath[3] = '\0';
  652.         break;
  653.    }
  654.  
  655.    gotorc(VOL_ROW,PATH_COL+1);
  656.    out_str(dirpath,65,' ');
  657. }
  658.  
  659.  
  660. /*****************************************************************************
  661.                           A D J _ D I R _ D I S
  662.  *****************************************************************************/
  663.  
  664. adj_dir_dis() {        /* make sure current dir ent will be on screen */
  665.  
  666.    register int r, c;
  667.  
  668.    /* adjust bounds and redisplay dir tree if the current entry is not
  669.       displayed */
  670.  
  671.    r = curdir->row;  c = curdir->col;  /* cutout a level of indirection */
  672.  
  673.    if (!dir_on_screen(r,c)) {
  674.  
  675.       if (r >= drend)                  /* current below display? */
  676.          drbase = r - NAME_ROWS + 1;
  677.       else
  678.          if (r < drbase)               /* current above display? */
  679.             drbase = r;
  680.  
  681.       if (c >= dcend)                  /* current right of display? */
  682.          dcbase = c - DCOLS + 1;
  683.       else
  684.          if (c < dcbase)               /* current left of display? */
  685.             dcbase = c;
  686.  
  687.       drend = drbase + NAME_ROWS;      /* reset display end markers */
  688.       dcend = dcbase + DCOLS;
  689.  
  690.       return(1);                       /* tell caller to redisplay */
  691.    }
  692.  
  693.    return(0);                          /* no adjustment needed */
  694. }
  695.  
  696.  
  697. /*****************************************************************************
  698.                              F I N D I R
  699.  *****************************************************************************/
  700.  
  701. static struct dir_ent *
  702. findir() {             /* find the current dir_ent */
  703.  
  704.    register char *lcp;
  705.    char *cp = cw.dirbuf+3;
  706.    char dirname[MAX_NAMELEN+2];
  707.    register struct dir_ent *dp = &root;
  708.  
  709.    *dirpath = '\0';
  710.    strncat(dirpath,cw.dirbuf,3);       /* roots better be the same */
  711.  
  712.    while (strcmp(dirpath,cw.dirbuf) != 0) {    /* have we found it yet? */
  713.  
  714.       /* haven't found it yet, go down another dir level, also do some
  715.          protective error checks, I don't feel real secure 'bout this yet */
  716.  
  717.       if (dp == NULL || (dp = dp->subdir) == NULL || (lcp = cp) == NULL)
  718.          return(&root);                        /* shouldn't happen, but... */
  719.  
  720.       if (cp = strchr(cp+1,'\\')) {            /* isolate the next dir level */
  721.          *dirname = '\0';                      /*   in cw.dirbuf */
  722.          strncat(dirname,lcp,cp-lcp);
  723.       } else
  724.          strcpy(dirname,lcp);                  /* this must be the last level */
  725.  
  726.       strcat(dirpath,dirname);                 /* add dir name to full path */
  727.  
  728.       if (*(lcp = dirname) == '\\')            /* 1st doesn't have leading \ */
  729.          lcp++;                                /*   others do */
  730.  
  731.       /* check all siblings at this level until we find it (or run out?) */
  732.  
  733.       while (dp && strcmp(lcp,dp->name) != 0)
  734.          dp = dp->sibling;
  735.    }
  736.  
  737.    return(dp);                 /* this should be the one */
  738. }
  739.  
  740.  
  741. /*****************************************************************************
  742.                         D I R _ O N _ S C R E E N
  743.  *****************************************************************************/
  744.  
  745. static int
  746. dir_on_screen(r,c)     /* determine if dir name is displayed */
  747. register int r, c;
  748. {
  749.    return(r >= drbase && r < drend && c >= dcbase && c < dcend);
  750. }
  751.